#!/usr/local/bin/perl

# texi2strong v1.0 - © 1995 Jochen Scharrlach (jscharrl@ba-stuttgart.de)

# This program is freeware, i.e. you can freely use and distribute it.
# You may not sell this program or distribute modified versions without
# having the permission from the author.

# Usage: texi2strng <texinfo-file> <directory>

$RiscOS = 1;

$dirSep = "." if $RiscOS;
$dirSep = "/" if ! $RiscOS;

$protectedChars = '\*\/_#<>';
$refQuote = '<>=-';

$O = "\000"; # {
$C = "\001"; # }
$; = "\002";
$B = "\003"; # \
$A = "\004"; # @

%Commands = ("set", \&ComSet,
             "clear", \&ComClear,
             "ifclear", \&ComIfClear,
             "ifset", \&ComIfSet,
             "enumerate", \&ComEnumerate,
             "itemize", \&ComItemize,
             "item", \&ComItem,
             "itemx", \&ComItem,
             "end", \&ComEnd,
             "example", \&ComExample,
             "smallexample", \&ComExample,
             "lisp", \&ComExample,
             "smalllisp", \&ComExample,
             "ignore", \&ComIgnore,
             "titlepage", \&ComIgnore,
             "tex", \&ComIgnore,
             "shorttitlepage", \&DummyProc,
             "c", \&DummyProc,
             "comment", \&DummyProc,
             "cindex", \&ComIndex,
             "findex", \&ComIndex,
             "vindex", \&ComIndex,
             "kindex", \&ComIndex,
             "pindex", \&ComIndex,
             "tindex", \&ComIndex,
             "iftex", \&ComIfTex,
             "ifinfo", \&ComIfInfo,
             "node", \&ComNode,
             "bye", \&ComNode,               # write the last Node!
             "page", \&ComPage,
             "center", \&ComCentre,
             "include", \&ComInclude,
             "menu", \&ComMenu,
             "synindex", \&ComSynindex,
             "syncodeindex", \&ComSynindex,
	     "table", \&ComTable,
	     "vtable", \&ComTable,
	     "ftable", \&ComTable,
	     "printindex", \&ComPrintindex,
	     "display", \&ComDisplay,
	     "format", \&ComDisplay,
	     "flushleft", \&ComFlushleft,
	     "flushright", \&ComFlushright,
	     "quotation", \&ComQuotation,
	     "sp", \&ComSpace,
             "deftypefn", \&ComDeftypefn,
             "deftypefun", \&ComDeftypefun,
             "deftypevar", \&ComDeftypevar,
             "defop", \&ComDefop,
#headings:
            "chapter" => \&ComOneline,
	    "section" => \&ComOneline,
	    "subsection" => \&ComOneline,
	    "subsubsection" => \&ComOneline,
	    "top" => \&ComOneline,
	    "unnumbered" => \&ComOneline,
	    "unnumberedsec" => \&ComOneline,
	    "unnumberedsubsec" => \&ComOneline,
	    "unnumberedsubsubsec" => \&ComOneline,
	    "appendix" => \&ComOneline,
	    "appendixsec" => \&ComOneline,
	    "appendixsubsec" => \&ComOneline,
	    "appendixsubsubsec" => \&ComOneline,
	    "majorheading" => \&ComOneline,
	    "chapheading" => \&ComOneline,
	    "heading" => \&ComOneline,
	    "subheading" => \&ComOneline,
	    "subsubheading" => \&ComOneline,
#those should really be ignored:
 	     "contents", \&DummyProc,
             "shortcontents", \&DummyProc,
             "summarycontents", \&DummyProc,
             "everyheading", \&DummyProc,
             "everyfooting", \&DummyProc,
             "evenheading", \&DummyProc,
             "evenfooting", \&DummyProc,
             "oddheading", \&DummyProc,
             "oddfooting", \&DummyProc,
             "heading", \&DummyProc,
             "footing", \&DummyProc,
             "footnotestyle", \&DummyProc,
             "cartouche", \&DummyProc,
             "settitle", \&DummyProc,
             "setfilename", \&DummyProc,
             "smallbook", \&DummyProc,
             "group", \&DummyProc,
             "finalout", \&DummyProc,
             "setchapternewpage", \&DummyProc,
             "need", \&DummyProc,
#not implemented (yet):
             "exdent", \&DummyProc,
             "paragraphindent", \&DummyProc,
             "vskip", \&DummyProc,
             "noindent", \&DummyProc,
             "defindex", \&WarnProc,
             "defcodeindex", \&WarnProc,
             "defcv", \&DummyProc,
             "deffn", \&DummyProc,
             "deffnx", \&DummyProc,
             "defindex", \&DummyProc,
             "defivar", \&DummyProc,
             "defmac", \&DummyProc,
             "defmethod", \&DummyProc,
             "defopt", \&DummyProc,
             "defspec", \&DummyProc,
             "deftp", \&DummyProc,
             "deftypevr", \&DummyProc,
             "defvr", \&DummyProc);

@ifs = ("ifclear", "ifset", "iftex", "ifinfo");

%Oneline = ("chapter" => "{fH2}",
	    "section" => "{fH3}",
	    "subsection" => "{fH4}",
	    "subsubsection" => "{fH5}",
	    "top" => "{fH1}",
	    "unnumbered" => "{fH2}",
	    "unnumberedsec" => "{fH3}",
	    "unnumberedsubsec" => "{fH4}",
	    "unnumberedsubsubsec" => "{fH5}",
	    "appendix" => "{fH2}",
	    "appendixsec" => "{fH3}",
	    "appendixsubsec" => "{fH4}",
	    "appendixsubsubsec" => "{fH5}",
	    "majorheading" => "{fH1}",
	    "chapheading" => "{fH2}",
	    "heading" => "{fH3}",
	    "subheading" => "{fH4}",
	    "subsubheading" => "{fH5}");
%Prefix = ("code" => $O."fCode".$C,
	   "kbd"  => $O."fCode".$C,
	   "key"  => $O."fCode".$C,
 	   "samp" => $O."fEmphasis".$C,
	   "var"  => $O."fStrong".$C,
	   "file" => $O."fCite".$C,
	   "dfn"  => $O."fUnderline".$C,
	   "cite" => $O."fCite".$C,
	   "emph" => $O."fEmphasis".$C,
	   "strong" => $O."fStrong".$C,
	   "quotation" =>  $O."fCite".$C,
	   "sc"  => "-");
%Postfix = ("code" => $O."f".$C,
	    "kbd" => $O."f".$C,
	    "key" => $O."f".$C,
	    "samp" => $O."f".$C,
	    "var" => $O."f".$C,
	    "file" => $O."f".$C,
	    "dfn" => $O."f".$C,
	    "cite"  => $O."f".$C,
            "emph" => $O."f".$C,
            "strong" => $O."f".$C,
            "quotation" =>  $O."f".$C,
	    "sc"  => "-");
%Special = ("copyright" => "©",
	    "bullet"    => "",
	    "dots"      => "Œ",
	    "w"         => "˜",
	    "minus"     => "-",
	    "result"    => "=\>",
	    "expansion" => "\<=\>",
	    "print"     => "»",
	    "error"     => "ERROR",
	    "equiv"     => "==",
	    "point"     => "-\>",
	    "TeX"       => "TeX",
	    "code"      => 1,
	    "kbd"       => 1,
	    "key"       => 1,
	    "samp"      => 1,
	    "var"       => 1,
	    "file"      => 1,
	    "dfn"       => 1,
	    "cite"      => 1,
	    "emph"      => 1,
	    "strong"    => 1,
	    "quotation" => 1,
	    "dfn"       => 1);
%unknownCommands =
    ("i" => 1,
     "b" => 1,
     "t" => 1,
     "r" => 1,
     "w" => 1,
     "dmn" => 1);
%unknownChars =
    ("refill" => 1,
     "i" => 1,
     "b" => 1,
     "t" => 1,
     "r" => 1,
     "w" => 1,
     "dmn" => 1,
     "asis" => 1);
%switches = ();
$currentFile = "";
%File2Node = ("!Root" => "Top");
%Node2File = ("Top" => "!Root",
              "top" => "!Root");
%Node2Menu = ();
@ThisNode = ();

$ConceptIndex = {};
$FunctionIndex = {};
$VariableIndex = {};
$KeystrokeIndex = {};
$ProgramIndex = {};
$DatatypeIndex = {};

%IndexCommands =
    ("cindex" => \$ConceptIndex,
     "findex" => \$FunctionIndex,
     "vindex" => \$VariableIndex,
     "kindex" => \$KeystrokeIndex,
     "pindex" => \$ProgramIndex,
     "tindex" => \$DatatypeIndex );
%IndexRefs =
    ("cp" => \$ConceptIndex,
     "fn" => \$FunctionIndex,
     "vr" => \$VariableIndex,
     "ky" => \$KeystrokeIndex,
     "pg" => \$ProgramIndex,
     "tp" => \$DatatypeIndex );

$MenuFlag = 0;
$ifCounter = 0;
$ignoreIfCounter = 0;
$ignoreIt = 1;
@Dokument = ();

$unknown = 0;
$numberedList = 1;
$normalList = 2;
$tableList = 3;

@listStack = ();
$listType = $unknown;
$listItemPrefix = 0;

# ****** Das Hauptprogramm:

print "Compile $ARGV[0]...\n";
# open (OUT, ">$ARGV[1]/!Root") || die "Couldn't open output!\n";
# $currentFile = "!Root";
compileFile($ARGV[0]);
close OUT;

# ****** Subroutinen:

sub compileFile {
    local($file) = @_;
#  local(FILE);
    local($cmd, $args, $line, $stat, $block, $_, $1, $2, $3, $node);
    $stat = 0;

    open (HANDLE, $file) || die "Can't open $file!\n";
#  warn "File $file opened!\n";
    @Dokument = <HANDLE>;
    close HANDLE;

    do {
	$block = "";
	while (($line = shift(@Dokument)) && !($MenuFlag && $line =~ /^\*/) &&
	       (! ($line =~ /^@(\w+)\b/ && $Commands{$1})))
	{
	    $block .= $line;
	}

	if (!$ignoreIfCounter)
	{
	    &output(&translate($block));
	}
	if ($line =~ /^@(\w+)\s*(.*)\s*$/ && $Commands{$1})
	{
	    $cmd = $1;
	    $args = $2;
	    $args =~ s/(\S)\s+$/$1/;

	    if ($ignoreIfCounter)
	    {
		$ignoreIfCounter++ if (grep(/^$cmd$/, @ifs));
		$ignoreIfCounter-- if ($cmd eq "end" && grep(/^$args$/, @ifs));
	    }
	    elsif ($Commands{$cmd} == \&ComIgnore)
	    {
		while (($line = shift(@Dokument)) &&
		       !($line =~ /^\@end $cmd/ ))
		{  }
	    }
	    else
	    {
#        $args = translate($args) if $cmd ne "c";
		&{$Commands{$cmd}}($cmd, translate($args)) if $Commands{$cmd} && ($cmd ne "c");
	    }
	}
	elsif ($MenuFlag && $line =~ /^\* ([^:]+)::(.*)/)
	{
	    $cmd = translate($1);
	    $args = translate($2);
	    output(MakeRef($cmd,Ref2File($cmd)).":".$args."\n");
	    $Node2Menu{$cmd} = $currentNode;
	}
	elsif ($MenuFlag && $line =~ /^\* ([^:]+):\s*(\S[^\.]*)\.(.*)/)
	{
	    $cmd = translate($1);
	    $node = translate($2);
	    $args = translate($3);
	    output(MakeRef($cmd,Ref2File($node)).":".$args."\n");
	    $Node2Menu{$node} = $currentNode;
	}
    } while ($_ = @Dokument);
}

sub translate {
    local($_) = @_;
    local($1, $2);

    s/\@\@/$A/g;
    s/\\/$B/g;

    s/\@c .*$//g;
    s/\@comment .*$//g;

#    s/\\([$quoteChars])/$;$1/g;
    s/\@{/$;$O/g;
    s/\@}/$;$C/g;
    s/\@://g;
    s/\@\././g;

    s/([$protectedChars])/$;$1/g;
    s/\@$;\*\n/\n# (line break)\n/g;
    s/\@$;\*/\n# (line break)\n/g;

    while (s/\@(\w+){([^{}]*)}/&ComAttribute($1, $2)/eg)
    { };
    s/@(\w+)\b/&ComSpecial($1)/eg;	#
    return rebuild($_);
}

sub rebuild {
    local ($_) = @_;
    s/$A/\@/g;
    s/$B/\\\\/g;
    s/$;/\\/g;
    s/$O/\{/g;
    s/$C/\}/g;

    return $_;
}

sub ComSet {
    local($cmd, $args) = @_;

    if ($args =~ /^(\w+)\s+(.*)$/)
    {
	$switches{$1} = $2;
    }
    else
    {
	$switches{$args} = 1;
    }
}
sub ComClear {
    local($cmd, $args) = @_;
    $switches{$args} = 0;
}
sub ComQuotation {
    local($cmd, $args);
    output("#fCite\n");
}
sub ComAttribute {
    local($cmd, $args) = @_;

    return ComSpecial($cmd, $args) if $args eq "";
    return uc($args) if $cmd eq "sc";
    return $switches{$args} if $cmd eq "value";
    return ComFootnote($args) if $cmd eq "footnote";
    return ComXRef($cmd, $args) if $cmd eq "ref" || $cmd eq "xref" ||
                                   $cmd eq "pxref" || $cmd eq "inforef";
    if (!$Prefix{$cmd} && !$unknownCommands{$cmd})
    {
	$unknownCommands{$cmd} = 1;
	warn "Command $cmd unknown!\n";
    }
    return $Prefix{$cmd}.$args.$Postfix{$cmd};
}
sub ComFootnote {
    local ($text) = @_;
    $noOfFootnotes++;
    push (@Footnotes, "($noOfFootnotes) ".translate($text)."\n\n");

    return "{fEmphasis}($noOfFootnotes){f}";
}
sub ComSpecial {
    local($cmd) = @_;

    if (!$Special{$cmd} && !$unknownChars{$cmd})
    {
	$unknownChars{$cmd} = 1;
	warn "Special character $cmd unknown!";
        warn "  next line: $Dokument[0]";
    }
    if ($Special{$cmd} == 1)
    {
	return $Prefix{$cmd};
    }
    else
    {
	return $Special{$cmd};
    }
}
sub ComIfSet {
    local($cmd, $args) = @_;
    if ($switches{$args})
    {
	$ifCounter++;
    }
    else
    {
	$ignoreIfCounter++;
    }
}
sub ComIfClear {
    local($cmd, $args) = @_;
    if (!$switches{$args})
    {
	$ifCounter++;
    }
    else
    {
	$ignoreIfCounter++;
    }
}
sub ComIfTex {
    local($cmd, $args) = @_;
    $ignoreIfCounter++;
}
sub ComIfInfo {
    local($cmd, $args) = @_;
    $ifCounter++;
}
sub ComEnumerate {
    local($cmd, $args) = @_;
    push (@listStack, [$listType, $listItemPrefix, $listItemIndex]);
    $listType = $numberedList;
    $listItemPrefix = $args;
    $listItemPrefix = 1 if $args eq "";
    $listItemIndex = 0;
    output ("#Indent +4\n");
}
sub ComItemize {
    local($cmd, $args) = @_;
    push (@listStack, [$listType, $listItemPrefix, $listItemIndex]);
    $listType = $normalList;
    $listItemPrefix = $args;
    $listItemIndex = 0;
    output ("#Indent +4\n");
}
sub ComTable {
    local($cmd, $args) = @_;
    push (@listStack, [$listType, $listItemPrefix, $listItemIndex]);
    $listType = $tableList;
    $listItemPrefix = $args;
    if ($cmd eq "ftable")
    {
	$listItemIndex = \$FunctionIndex;
    }
    elsif ($cmd eq "vtable")
    {
	$listItemIndex = \$VariableIndex;
    }
    else
    {
	$listItemIndex = 0;
    }
    output ("#Indent +4\n");
}
sub ComItem {
    local($cmd, $args) = @_;

#    output ("\n") if $cmd eq "item";

    if ($listType == $numberedList)
    {
	output(" $listItemPrefix. ");
	$listItemPrefix++;
    }
    elsif ($listType == $tableList)
    {
	if ($listItemPrefix =~ /^{/)
	{
	    output("#Indent\n".$listItemPrefix.$args."{f}\n#Indent +4\n");
	}
	else
	{
	    output("#Indent\n$listItemPrefix$args\n#Indent +4\n");
	}
	IndexInsert($listItemIndex, $args) if $listItemIndex;
    }
    else
    {
	output("\n $listItemPrefix ");
    }
}
sub IndexInsert {
    ($i, $a) = @_;
    $a =  RemoveAttributes($a);
    $$i->{$a} = $currentFile if ! $$i->{$a};
}
sub ComExample {
    local($cmd, $args) = @_;
    output ("#Wrap off\n#fCode\n");
}
sub ComDisplay {
    local($cmd, $args) = @_;
    output ("#Wrap off\n");
}
sub ComIgnore {
    local($cmd, $args) = @_;
    $ignoreIt = 1;
}
sub ComC {
    local($cmd, $args) = @_;
    output ("# $args\n");
}
sub ComIndex {
    local($cmd, $args) = @_;
    local($hash);

    if (!($hash = $IndexCommands{$cmd}))
    {
	warn "Unknown index command: $cmd\n";
	return;
    }
#    warn "Index: $cmd $args\n";
    $hash = $$hash;
    $args = RemoveAttributes(rebuild($args));
    $hash->{$args} = $currentFile if ! $hash->{$args};
}
sub ComSynindex {
    local($cmd, $args) = @_;
    local($fromhash, $tohash, $_, $1, $2);

    $_ = $args;

    if (! /^\s*(\w+)\s+(\w+)\s*$/)
    {
	warn "Wrong syncodeindex-syntax: $args\n";
	return;
    }
    $fromhash = $IndexRefs{$1};
    $tohash = $IndexRefs{$2};

    if (!($fromhash && $tohash))
    {
	warn "Unknown index commands: >$1< >$2<\n";
	return;
    }
    $$fromhash = $$tohash;
}
sub ComPrintindex {
    local($cmd, $args) = @_;
    local($_, $hash);
    if (!($hash = $IndexRefs{$args}))
    {
	warn "Index %args unknown!\n";
	return;
    }
    $hash = $$hash;
    output ("#Wrap off\n");
    for (sort(keys %$hash))
    {
	output(MakeRef($_,$hash->{$_})."\n");
    }
    output ("#Wrap on\n");
}

sub ComOneline {
    local($cmd, $args) = @_;

    output ($Oneline{$cmd}.$args."{f}\n");
}
sub ComPage {
    local($cmd, $args) = @_;
    output ("#Line\n");
}
sub ComNode {
    local($cmd, $args) = @_;
    local($panel, $holdPrev);
    local(@par);

    @par = split(/\s*,\s*/, $args);
    if ($currentFile)
    {
    	$nextNode = $par[0] if $nextNode eq "";
	$ThisNode[1] = "Previous: <".$prevNode."=>".Ref2File($prevNode)."> * "
	           if $prevNode ne "";
	$ThisNode[1] .= "Next: <".$nextNode."=>".Ref2File($nextNode)."> * "
		   if $nextNode ne "";
	$ThisNode[1] .= "Up: <".$upNode."=>".Ref2File($upNode).">"
		   if $upNode ne "";
        $ThisNode[1] .= "\n\n";

        open(OUT, ">".$ARGV[1].$dirSep.$currentFile)
	    || die "Couldn't open $currentFile!\n";

        print OUT @ThisNode;
	if ($noOfFootnotes)
	{
	    print OUT "#Line\n";
	    print OUT @Footnotes;
	}
        close OUT;
    }
    $holdPrev = $currentNode;
    ($currentNode, $nextNode, $prevNode, $upNode) = @par;
    $prevNode = $holdPrev if $prevNode eq "";
    $upNode = $Node2Menu{$currentNode} if $upNode eq "";

    @ThisNode = ("$currentNode\n", "", "#Wrap on\n");
    $currentFile = Ref2File($currentNode);
    $noOfFootnotes = 0;
    @Footnotes = ();
}
sub ComSetTitle {
    local($cmd, $args) = @_;
    # tja, ne Node halt...
}
sub ComSetFileName {
    local($cmd, $args) = @_;
    # tja, ne Node halt...
}
sub DummyProc {
    local($cmd, $args) = @_;
#    warn "Warning: $cmd not supported!!\n";
}
sub ComEmph {
    local($cmd, $args) = @_;
    output ("\n{fEmphasis} $args {f}\n");
}
sub ComCentre {
    local($cmd, $args) = @_;
    output ("#Align Centre\n$args\n#Align\n");
}
sub ComFlushleft {
    local($cmd, $args) = @_;
    output ("#Align left\n");
}
sub ComFlushright {
    local($cmd, $args) = @_;
    output ("#Align right\n");
}
sub ComMenu {
    local($cmd, $args) = @_;
    $MenuFlag = 1;
    output ("#Wrap off\n");
}
sub ComDeftypefn {
    local($cmd, $_) = @_;
    local(@a, $c, $t, $n);
    
    ($c, $t, $n, @a) = ParseArgs($_, 3);
    output(ucfirst($c).": $t $n @a\n#Indent +4\n");
    IndexInsert(\$FunctionIndex, $n);
}
sub ComDeftypefun {
    local($cmd, $_) = @_;
    local(@a, $c, $t);
    
    ($t, $n, @a) = ParseArgs($_, 2);
    output("Function: $t $n @a\n#Indent +4\n");
    IndexInsert(\$FunctionIndex, $n);
}
sub ComDeftypevar {
    local($cmd, $_) = @_;
    local(@a);
    
    ($t, $n, @a) = ParseArgs($_, 2);
    output("Variable: $t $n @a\n#Indent +4\n");
    IndexInsert(\$VariableIndex, $n);
}
sub ComDefop {
    local($cmd, $_) = @_;
    local(@a, $c, $t, $n);

    ($c, $t, $n, @a) = ParseArgs($_, 3);
    output(ucfirst($c).": $t::$n @a\n#Indent +4\n");
    IndexInsert(\$FunctionIndex, $n." on ".$t);
}
sub ParseArgs {
    local($line, $i) = @_;
    local(@a, $1, $2);

    @a = ();
    $2 = "";
    
    while ($line ne "" && ($line =~ /^\s*{([^{}]*)}(.*)$/ ||
                           $line =~ /^\s*(\S+) (.*)$/ ||
                           $line =~ /^\s*(\S+)$/) && $i > 0)
    {
        push (@a, $1);
        $line = $2;
        $2 = "";
        $i--;
    }
    return (@a, $line);
}
        
sub ComEnd {
    local($cmd,$args) = @_;

    if (grep(/^$args$/, @ifs))
    {
	$ifCounter--;
    }
    elsif ($args eq "itemize" || $args eq "enumerate" ||
	   $args eq "table" || $args eq "ftable" || $args eq "vtable")
    {
	($listType, $listItemPrefix, $listItemIndex) = @{pop(@listStack)};
	output ("\n#Indent\n");
    }
    elsif ($args eq "example" || $args eq "smallexample" ||
    	   $args eq "lisp" || $args eq "smalllisp")
    {
	output ("#f\n#Wrap on\n");
    }
    elsif ($args eq "menu")
    {
	$MenuFlag = 0;
        output ("#Wrap on\n");
    }
    elsif ($args eq "display" ||$args eq "format")
    {
        output ("#Wrap on\n");
    }
    elsif ($args eq "flushleft" ||$args eq "flushright")
    {
        output ("#Align\n");
    }
    elsif ($args eq "quotation")
    {
        output ("#f\n");
    }
    elsif ($args eq "deftypefn" || $args eq "deftypefun" ||
           $args eq "deftypevar" || $args eq "defop")
    {
        output ("#Indent\n");
    }
    elsif ($args eq "group" || $args eq "cartouche")
    {
	# don't care
    }
    else
    {
      warn "Unknown end sequence: $args\n";
    }
}
sub ComInclude {
    local($cmd,$args) = @_;
    local(@help);
    $args =~ s/\./\//g if $RiscOS;
    open (HANDLE, $args) || die "Can't open $args\n";
    @help = <HANDLE>;
    close HANDLE;
    @Dokument = (@help, @Dokument);
}
sub ComXRef {
    local ($cmd, $_) = @_;
    local ($node, $cross, $topic, $text, @args);

    s/\n/ /g;

    ($node, $cross, $text) = split(/\s*,\s*/, $_);
    $cross = $node if $cross eq "";
    $text = ": $text" if $text ne "";

#    warn "Converted: $_ -> <$label=>$file>";
    $node = Ref2File($node);
    $cross = RemoveInternalAttributes($cross);
    return "\\*Note <$cross=>$node>$text";
}
sub ComSpace {
    local($cmd, $args) = @_;
    for (1 .. $args)
    {
        output ("\n");
    }
}
sub RemoveInternalAttributes {
    local($_) = @_;

    s/$;$O/\\{/g;
    s/$;$C/\\}/g;
    s/$O[^$O$C]*$C//g;
    s/\\{/$;$O/g;
    s/\\}/$;$C/g;
    return $_;
}
sub RemoveAttributes {
    local($_) = @_;

    s/\\{/$;$O/g;
    s/\\}/$;$C/g;
    s/{[^{}]*}//g;
    s/$;$O/\\{/g;
    s/$;$C/\\}/g;
    return $_;
}
sub translateNode {
    local ($_) = @_;
    s/[\W]//g;
    return (substr($_, 0, 10));
}
sub MakeRef {
    local ($ref, $node) = @_;
    if ($ref =~ /^[$refQuote]/)
    {
      return "<\\".$ref."=>".$node.">";
    }
    else
    {
      return "<".$ref."=>".$node.">";
    }
}
sub Ref2File {
    local ($_) = @_;
    local ($f);

#    s/{[^}]*}//g;

    if ( $Node2File{$_} ne "")
    {
	return $Node2File{$_};
    }
    else
    {
	$f = translateNode($_);
	$f = "A" if $f eq "";
	while ($File2Node{$f})
	{
	    $f++;
	}
	$File2Node{$f} = $_;
	$Node2File{$_} = $f;
#	warn "translated: $_ -> $f\n";
	return $f;
    }
}
sub output {
    local($line) = @_;
    push @ThisNode, $line;
}

